package com.liuboya.weibomodel.model;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.Collections;
import java.util.Objects;

/**
 * 描述:
 *
 * <p>
 * 返回data结构
 */
@Getter
@Setter
public class ApiResult<T> implements Serializable {

    /**
     * 处理成功
     */
    public static final int SUCC                  = 1001;
    /**
     * 处理失败
     */
    public static final int FAIL                  = 1002;
    /**
     * 请求需要token的接口但接口参数没有带上token
     */
    public static final int NOT_AUTH              = 1003;
    /**
     * 参数带上了token，但token错误，库中无对应的数据
     */
    public static final int ERROR_TOKEN           = 1004;
    /**
     * 用户请求次数太多，禁止请求
     */
    public static final int VISIT_LIMIT           = 1005;
    /**
     * 算法错误
     */
    public static final int SIGN_ERROR            = 2000;
    /**
     * 非VIP用户请求VIP接口
     */
    public static final int VIP_AUTH_INSUFFICIENT = 1006;
    /**
     * 小程序用户未授权unionID
     */
    public static final int AUTH_ERROR            = 1007;
    /**
     * 搜索引擎异常
     */
    public static final int SEARCH_ENGINE_FAIL    = 1008;
    /**
     * 非抖参谋VIP
     */
    public static final int NOT_DSB_VIP           = 1009;
    /**
     * 请求数量权限
     */
    public static final int REQUEST_NUMBER_AUTH   = 1010;

    /**
     * 业务异常
     */
    public static final int BUSINESS_ERROR = 1024;

    /**
     * 参数异常
     */
    public static final int ARGUMENT_ERROR = 1044;

    /**
     * http响应体：成功
     */
    private static final ApiResult SUCCESS_RESULT = success(Collections.emptyMap());

    /**
     * http响应体：成功，无数据
     */
    private static final ApiResult EMPTY_SUCCESS_RESULT = success((Object) null);

    /**
     * 结果是否成功
     */
    private boolean success;

    /**
     * 错误码
     */
    private int code;

    /**
     * 错误信息
     */
    private String message;

    /**
     * 内部结构对象
     */
    private Result result;


    public ApiResult(boolean success, int code, String message, T data) {
        this.success = success;
        this.code = code;
        this.message = message;
        Result result = new Result<T>();
        if (Objects.equals(data, null)) {
            this.result = null;
        } else {
            result.data = data;
        }
        this.result = result;
    }

    public ApiResult(boolean success, int code, String message, T data, Integer count) {
        this.success = success;
        this.code = code;
        this.message = message;
        Result result = new Result<T>();
        if (Objects.equals(data, null)) {
            this.result = null;
        } else {
            result.data = data;
            result.count = count;
        }
        this.result = result;
    }

    /**
     * 返回成功处理结果
     */
    public static <T> ApiResult<T> success() {
        return SUCCESS_RESULT;
    }

    /**
     * 返回无data结点的成功数据
     */
    public static <T> ApiResult<T> empty() {
        return EMPTY_SUCCESS_RESULT;
    }

    /**
     * 根据给定的数据返回成功处理结果
     *
     * @param data  业务数据体
     * @param count 总条数
     */
    public static <T> ApiResult<T> success(T data, int count) {
        return new ApiResult<T>(true, SUCC, null, data, count);
    }


    /**
     * 根据给定的数据返回成功处理结果
     *
     * @param data 业务数据体
     */
    public static <T> ApiResult<T> success(T data) {
        return new ApiResult<T>(true, SUCC, null, data);
    }

    /**
     * 在某些特殊场景下，在返回成功的情况下，也需要错误码
     *
     * @param data    业务数据体
     * @param code    错误码
     * @param message 错误信息
     */
    public static <T> ApiResult<T> success(T data, int code, String message) {
        return new ApiResult<T>(true, code, message, data);
    }

    /**
     * 返回错误的结果处理对象
     *
     * @param code    错误码
     * @param message 错误描述信息
     */
    public static <T> ApiResult<T> failure(int code, String message) {
        return new ApiResult<T>(false, code, message, null);
    }


    /**
     * 返回错误的结果处理对象
     *
     * @param code 错误码
     * @return 错误返回结果
     */
    public static <T> ApiResult<T> failure(int code) {
        return new ApiResult<T>(false, code, null, null);
    }

    /**
     * 返回错误的结果处理对象
     *
     * @return 错误返回结果
     */
    public static <T> ApiResult<T> failure() {
        return new ApiResult<T>(false, FAIL, null, null);
    }

    /**
     * 返回错误的结果处理对象
     *
     * @param message 错误信息
     * @return 错误返回结果
     */
    public static <T> ApiResult<T> failure(String message) {
        return new ApiResult<T>(false, FAIL, message, null);
    }


    @Data
    private class Result<T> {
        /**
         * 处理结果，根据具体接口来决定。
         * 定义成泛型，有利于在java端从json反序列化的时候，直接映射成所需要的对象。
         * <p>注：在有错误的时候，这个值一定要设置成null，一可以减少返回字节数，二是在反序列时不会因为类型对不上，而导致出错
         */
        private T data;

        /**
         * 分页数量
         */
        private Integer count;
    }


}

